Skip to main content
Conveniences for testing function components, LiveViews, and LiveComponents.

Overview

The Phoenix.LiveViewTest module provides a comprehensive testing API for Phoenix LiveView applications. It supports testing function components, stateful LiveViews, and LiveComponents through process communication that simulates browser interactions.

Testing Function Components

render_component/3

Renders a component for testing.
render_component(component, assigns \\ %{}, opts \\ [])
component
function | module
required
Either a function component (anonymous function) or a stateful component module
assigns
map
Assigns to pass to the component
opts
keyword
Options including :router if the component uses routing

Examples

Testing a function component:
import Phoenix.LiveViewTest

test "greets user" do
  assert render_component(&MyComponents.greet/1, name: "Mary") =~
           "Hello, Mary!"
end
Testing a stateful component:
test "renders user component" do
  assert render_component(MyComponent, id: 123, user: %User{}) =~
           "some markup"
end

rendered_to_string/1

Converts a rendered template to a string.
rendered_to_string(rendered)

Example

import Phoenix.Component
import Phoenix.LiveViewTest

test "greets" do
  assigns = %{}
  assert rendered_to_string(~H"""
         <MyComponents.greet name="Mary" />
         """) == "<div>Hello, Mary!</div>"
end

Testing LiveViews

live/2 and live/3

Spawns a connected LiveView process.
live(conn, path \\ nil, opts \\ [])
conn
Plug.Conn.t()
required
The test connection
path
string
The path to navigate to. If nil, uses a previously rendered conn
opts
keyword
Options:
  • :on_error - Either :raise or :warn for error handling (default: :raise)
result
{:ok, view, html} | {:error, reason}
Returns a tuple with the view, HTML on success, or error on redirect

Examples

Connected mount:
test "connected mount", %{conn: conn} do
  {:ok, view, html} = live(conn, "/thermo")
  assert html =~ "Temperature"
end
Two-step mount:
test "disconnected and connected mount", %{conn: conn} do
  conn = get(conn, "/my-path")
  assert html_response(conn, 200) =~ "<h1>Disconnected</h1>"
  
  {:ok, view, html} = live(conn)
  assert html =~ "<h1>Connected</h1>"
end
Handling redirects:
test "redirected mount", %{conn: conn} do
  assert {:error, {:redirect, %{to: "/somewhere"}}} = live(conn, "/path")
end

live_isolated/3

Spawns a connected LiveView process in isolation.
live_isolated(conn, live_view, opts \\ [])
Useful for testing LiveViews that are not directly routable.
opts
keyword
Options:
  • :session - Session data for the LiveView
  • :on_error - Error handling mode

Example

test "isolated mount" do
  {:ok, view, html} = 
    live_isolated(conn, MyAppWeb.ClockLive, session: %{"tz" => "EST"})
  
  assert html =~ "EST"
end

put_connect_params/2

Puts connect params for LiveView connections.
put_connect_params(conn, params)

Example

{:ok, view, html} =
  conn
  |> put_connect_params(%{"param" => "value"})
  |> live_isolated(MyLive, session: %{"tz" => "EST"})

Event Testing Functions

render_click/1 and render_click/3

Sends a click event and returns the rendered result.
render_click(element, value \\ %{})
render_click(view, event, value)

Examples

test "increment temperature" do
  {:ok, view, _html} = live(conn, "/thermo")
  
  # Using element
  assert view
         |> element("button#inc")
         |> render_click() =~ "31℉"
  
  # Direct event
  assert render_click(view, :inc, %{}) =~ "31℉"
end

render_submit/1 and render_submit/3

Sends a form submit event.
render_submit(element, value \\ %{})
render_submit(view, event, value)

Examples

test "form submission" do
  {:ok, view, _html} = live(conn, "/users/new")
  
  assert view
         |> form("#user-form", user: %{name: "Alice"})
         |> render_submit() =~ "User created"
end

render_change/1 and render_change/3

Sends a form change event.
render_change(element, value \\ %{})
render_change(view, event, value)

Example

test "form validation" do
  {:ok, view, _html} = live(conn, "/form")
  
  assert view
         |> form("#my-form", user: %{email: "invalid"})
         |> render_change() =~ "must include @"
end

render_blur/1, render_focus/1, render_keydown/1, render_keyup/1

Send respective events and return rendered results.

Examples

# Blur event
assert view |> element("#email") |> render_blur() =~ "Field validated"

# Focus event
assert view |> element("#email") |> render_focus() =~ "Help text"

# Keydown event
assert view |> element("#input") |> render_keydown() =~ "Key pressed"

# Keyup event
assert view |> element("#input") |> render_keyup() =~ "Key released"

render_hook/3

Sends a hook event to the view or element.
render_hook(view_or_element, event, value \\ %{})

Examples

# To view
assert render_hook(view, :refresh, %{deg: 32}) =~ "32℉"

# To component
assert view
       |> element("#thermo-component")
       |> render_hook(:refresh, %{deg: 32}) =~ "32℉"

render_patch/2

Simulates a push_patch to the given path.
render_patch(view, path)

Example

html = render_patch(view, "/users?page=2")
assert html =~ "Page 2"

render_async/2

Awaits all async tasks and renders the result.
render_async(view_or_element, timeout \\ 100)

Example

{:ok, lv, html} = live(conn, "/path")
assert html =~ "loading data..."
assert render_async(lv) =~ "data loaded!"

Element Selection

element/3

Returns an element to scope a function to.
element(view, selector, text_filter \\ nil)
view
View.t()
required
The LiveView
selector
string
required
CSS selector
text_filter
string | Regex
Filter by text content

Examples

view |> element("#user-13")
view |> element("button", "Save")
view |> element("a", ~r/Edit/)
view |> element(~s{[id="foo.bar.baz"]})

has_element?/1 and has_element?/3

Checks if an element exists.
has_element?(element)
has_element?(view, selector, text_filter \\ nil)

Examples

assert has_element?(view, "#user-1")
refute has_element?(view, "button", "Delete")
assert view |> element("#notice") |> has_element?()

form/3

Returns a form element.
form(view, selector, form_data \\ %{})

Example

view
|> form("#user-form", user: %{name: "Alice", email: "alice@example.com"})
|> render_submit()

put_submitter/2

Puts a submitter element on a form.
put_submitter(form, element_or_selector)

Example

form = view |> form("#my-form")

assert form
       |> put_submitter("button[name=save]")
       |> render_submit() =~ "Saved"

File Upload Testing

file_input/4

Builds a file input for testing uploads.
file_input(view, form_selector, name, entries)
entries
list
List of maps with upload metadata:
  • :name - File name
  • :content - Binary content
  • :type - MIME type
  • :size - File size in bytes
  • :last_modified - Timestamp

Example

avatar = file_input(lv, "#upload-form", :avatar, [
  %{
    last_modified: 1_594_171_879_000,
    name: "myfile.jpeg",
    content: File.read!("test/fixtures/myfile.jpg"),
    size: 1_396_009,
    type: "image/jpeg"
  }
])

assert render_upload(avatar, "myfile.jpeg") =~ "100%"

assert_patch/2 and assert_patch/3

Asserts a live patch occurred.
assert_patch(view, timeout \\ 100)
assert_patch(view, to, timeout \\ 100)

Examples

render_click(view, :edit)
path = assert_patch(view)
assert path =~ ~r/\/edit/

render_click(view, :next)
assert_patch(view, "/page/2")

assert_redirect/2 and assert_redirect/3

Asserts a redirect occurred.
assert_redirect(view, timeout \\ 100)
assert_redirect(view, to, timeout \\ 100)

Examples

render_click(view, :save)
{path, flash} = assert_redirect(view)
assert flash["info"] == "Saved"

render_click(view, :cancel)
flash = assert_redirect(view, "/")

refute_redirected/1 and refute_redirected/2

Refutes a redirect occurred.
refute_redirected(view)
refute_redirected(view, to)

LiveComponent Testing

live_children/1

Returns the list of child LiveViews.
live_children(parent_view)

Example

{:ok, view, _html} = live(conn, "/parent")
assert [child_view] = live_children(view)
assert render_click(child_view, :action) =~ "result"

find_live_child/2

Gets a nested LiveView child by ID.
find_live_child(parent_view, child_id)

Example

{:ok, view, _html} = live(conn, "/parent")
clock_view = find_live_child(view, "clock")
assert render_click(clock_view, :snooze) =~ "snoozing"

Utility Functions

render/1

Returns the HTML string of the rendered view or element.
render(view_or_element)

with_target/2

Sets the target for events.
with_target(view, target)

Example

view
|> with_target("#user-1,#user-2")
|> render_click("Hide", %{})

page_title/1

Returns the most recent page title.
page_title(view)

Example

render_click(view, :navigate)
assert page_title(view) =~ "Dashboard"

open_browser/1

Opens the default browser to display current HTML.
open_browser(view_or_element)
Useful for debugging tests.